﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ApplicationLibrary;
using ApplicationLibrary.CounterManager;
using ApplicationLibrary.DBManager;
using ApplicationLibrary.ExtendedControls;
using ApplicationLibrary.Preferences;
using ApplicationLibrary.SqlConnector;
using Plumber.Accounting.Forms;
using Plumber.Accounting.Library;
using Plumber.Accounting.ModuleData;
using Plumber.Accounting.Preferences;
using Plumber.Sales.ModuleData;
using Plumber.Sales.Preferences;

namespace Plumber.Accounting.Scrounger
{
    internal class SaleScrounger : ApplicationLibrary.DBManager.Scrounger
    {
        private const string JournalEntrySlave = "JOURNALENTRSLAVE";

        private UserTabControl<TabJE> UtctabJE = null;
        private TabJE tabJE = null;
        private Sales.Forms.SalesInvoice frm;
        private AccountingPref AccountingPref = null;
        private DRJournalEntryByDocumentNo drJEByNo = null;
        private DBManager dbManager = null;
        private SalesPref SalesPref = null;

        public SaleScrounger(iScrounger frm)
            : base(frm)
        {
            this.frm = (Sales.Forms.SalesInvoice)frm;

            AccountingPref = new PreferencesManager<AccountingPref>(this.frm.Name, null).ReadPreference();
            SalesPref = new PreferencesManager<SalesPref>(this.frm.Name, null).ReadPreference();
        }

        public override bool OnEnableToolbarButtons(ToolStripButton button, DBManager dbManager)
        {
            if (button.Name == "CreatePayment")
            {
                if (dbManager.Status != DBMode.Browse)
                    return false;
                if (dbManager.Pos == -1)
                    return false;

                return !frm.CkbPayed.Checked;
            }
            return base.OnEnableToolbarButtons(button, dbManager);
        }

        public override void InitializerComponent()
        {
            if (AccountingPref.EnableLink)
            {
                UtctabJE = new UserTabControl<TabJE>(Properties.Resources.TD_JournalEntries);
                UtctabJE.Name = "tpgJE";

                frm.MasterTabControl.Controls.Add(UtctabJE);
                tabJE = UtctabJE.UserControl;
            }

            frm.CkbPayed.CheckedChanged += new EventHandler(CkbPayed_CheckedChanged);
            base.InitializerComponent();
        }

        void CkbPayed_CheckedChanged(object sender, EventArgs e)
        {
            if (frm.CkbPayed.Checked)
                frm.NtbAmountPayed.Double = frm.NtbTotal.Double;
        }

        private void ManageTabJE(bool visible)
        {
            TabPage tp = frm.MasterTabControl.TabPages["tpgJE"];
            if (tp == null)
            {
                if (visible)
                    frm.MasterTabControl.TabPages.Add(UtctabJE);
            }
            else
            {
                if (!visible)
                    frm.MasterTabControl.TabPages.Remove(UtctabJE);
            }
        }

        public override void OnAttachData(DBManager dbManager)
        {
            this.dbManager = dbManager;

            if (AccountingPref.EnableLink)
            {
                dbManager.AddSlave(JournalEntrySlave, false);
                tabJE.OnAttachData(dbManager);
            }
            ManageTabJE(AccountingPref.EnableLink);
            base.OnAttachData(dbManager);
        }

        public override void OnPrepareAuxData()
        {
            if (AccountingPref.EnableLink)
            {
                tabJE.AutoResizeColumns();
                tabJE.CalculateTotal();
            }

            base.OnPrepareAuxData();
        }

        public override void OnBindData()
        {
            if (AccountingPref.EnableLink)
                tabJE.OnBindData(frm);

            base.OnBindData();
        }

        public override void OnCustomizeToolbar(ToolStrip toolstrip)
        {
            if (AccountingPref.EnableLink)
                frm.AddCustomButton("CreatePayment", Properties.Resources.T_CreatePayment, Properties.Resources.B_CreatePayment, false);
            base.OnCustomizeToolbar(toolstrip);
        }

        public override void OnDisableControlsForEdit()
        {
            if (AccountingPref.EnableLink && frm.Name == "SalesInvoice")
            {
                frm.CtbPaymentDate.Enabled = false;
                frm.CkbPayed.Enabled = false;
                frm.NtbAmountPayed.Enabled = false;
            }
            base.OnDisableControlsForEdit();
        }

        public override void OnCustomButtonClick(ToolStripButton button)
        {
            if (button.Name == "CreatePayment")
            {
                CreatePayment cp = new CreatePayment();
                Double total = frm.CkbRestraint.Checked
                                ? frm.NtbTotal.Double - frm.NtbRestraint.Double
                                : frm.NtbTotal.Double;
                cp.InvoiceAmount = total;
                cp.AmountToPayed = total - frm.NtbAmountPayed.Double;
                frm.OpenNewForm(cp, true);
                if (cp.DialogResult == System.Windows.Forms.DialogResult.OK &&
                    CreatePayment(cp.AmountToPayed, cp.BankCash, cp.BankCashCode))
                {
                    MyMessageBox(Properties.Resources.Msg_PaymentOK, Properties.Resources.Msg_Payment, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    dbManager.Refresh();
                    frm.ManageOperationButton();
                }
            }
            base.OnCustomButtonClick(button);
        }

        public override bool OnBeforeSave()
        {
            if (AccountingPref.EnableLink)
            {
                string docNo = string.Empty, code = string.Empty;
                double amount = 0;
                Double total = frm.CkbRestraint.Checked
                            ? frm.NtbTotal.Double - frm.NtbRestraint.Double
                            : frm.NtbTotal.Double;

                if (SalesPref.LockSalesPayed && SearchPayment(ref docNo, out amount, out code) && (amount != total || code != frm.RdrCode.Text))
                {
                    MyMessageBox(string.Format(Properties.Resources.Msg_SaveInvoice, docNo), Properties.Resources.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return false;
                }
            }
            return base.OnBeforeSave();
        }

        public override bool OnBeforeDelete()
        {
            if (AccountingPref.EnableLink)
            {
                string docNo = string.Empty, code = string.Empty;
                double amount = 0;
                if (SalesPref.LockSalesPayed && SearchPayment(ref docNo, out amount, out code))
                {
                    MyMessageBox(string.Format(Properties.Resources.Msg_DeleteInvoice, docNo), Properties.Resources.Warning, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return false;
                }
                if (AccountingPref.IsTaxEnabled(frm.CtbDate.Today))
                {
                    using (JournalEntriesSalePurchaseCreator jC = new JournalEntriesSalePurchaseCreator(frm.GetInvoiceType))
                    {
                        string DocNo = jC.SearchFromDocumentNo(frm.CbbManager.GetValue<string>(), frm.RdrCode.Text, frm.FncSalesNo.ToString(false));
                        if (DocNo != "" && jC.Find(DocNo))
                            return jC.Delete();
                    }
                }
                else
                {
                    using (JournalEntriesCreator jC = new JournalEntriesCreator())
                    {
                        string DocNo = jC.SearchFromDocumentNo(frm.CbbManager.GetValue<string>(), frm.RdrCode.Text, frm.FncSalesNo.ToString(false));
                        if (DocNo != "" && jC.Find(DocNo))
                            return jC.Delete();
                    }
                }
            }
            return base.OnBeforeDelete();
        }

        public override bool OnAfterSave()
        {
            if (!AccountingPref.EnableLink)
                return base.OnAfterSave();

            if (AccountingPref.IsTaxEnabled(frm.CtbDate.Today))
            {
                using (JournalEntriesSalePurchaseCreator jC = new JournalEntriesSalePurchaseCreator(frm.GetInvoiceType))
                {
                    string DocNo = string.Empty;
                    if (!frm.IsNew)
                        DocNo = jC.SearchFromDocumentNo(frm.AnagType, frm.AnagCode, frm.FncSalesNo.ToString(false));
                    if (!DocNo.IsEmpty() && jC.Find(DocNo))
                        return EditJournalEntriesSalePurchase(jC, frm.FncSalesNoRef);
                    else
                        return NewJournalEntriesSalePurchase(jC);
                }
            }
            else
            {
                using (JournalEntriesCreator jC = new JournalEntriesCreator())
                {
                    string DocNo = jC.SearchFromDocumentNo(frm.AnagType, frm.AnagCode, frm.FncSalesNo.ToString(false));
                    if (DocNo != "" && jC.Find(DocNo))
                        return EditJournalEntries(jC);
                    else
                        return NewJournalEntries(jC);
                }
            }
        }

        /// <summary>
        /// Modify existing journal entry to correct value
        /// </summary>
        /// <param name="jC"></param>
        /// <returns></returns>
        private bool EditJournalEntries(JournalEntriesCreator jC)
        {
            if (!jC.Edit())
                return false;

            string desc = string.Format(Properties.Resources.Msg_EmittedInvoice, frm.FncSalesNo.ToString(false), frm.CtbDate.Today.ToShortDateString());
            jC.SetHeader(frm.CtbDate.Today, desc);
            DataGridViewRowValues.SetValue<string>(jC.GetRow(0), PL_JournalEntryDetail.Description, desc);
            DataGridViewRowValues.SetValue<string>(jC.GetRow(1), PL_JournalEntryDetail.Description, desc);
            DataGridViewRowValues.SetValue<string>(jC.GetRow(1), PL_JournalEntryDetail.DocumentNo, frm.FncSalesNo.ToString(false));

            Double total = frm.CkbRestraint.Checked
                            ? frm.NtbTotal.Double - frm.NtbRestraint.Double
                            : frm.NtbTotal.Double;

            DataGridViewRowValues.SetValue<double>(jC.GetRow(0), PL_JournalEntryDetail.From, total);
            DataGridViewRowValues.SetValue<double>(jC.GetRow(0), PL_JournalEntryDetail.To, 0);
            DataGridViewRowValues.SetValue<double>(jC.GetRow(1), PL_JournalEntryDetail.From, 0);
            DataGridViewRowValues.SetValue<double>(jC.GetRow(1), PL_JournalEntryDetail.To, total);

            return jC.Save();
        }

        /// <summary>
        /// Create a journal entries relates to this invoice
        /// </summary>
        /// <param name="jC"></param>
        /// <returns></returns>
        private bool NewJournalEntries(JournalEntriesCreator jC)
        {
            if (!jC.AddNew())
                return false;

            string desc = string.Format(Properties.Resources.Msg_EmittedInvoice, frm.FncSalesNo.ToString(false), frm.CtbDate.Today.ToShortDateString());
            jC.SetHeader(frm.CtbDate.Today, desc);

            string masterType = jC.GetMasterTypeByType(MasterTypes.E_SaleInvoice);

            Double total = frm.CkbRestraint.Checked
                            ? frm.NtbTotal.Double - frm.NtbRestraint.Double
                            : frm.NtbTotal.Double;

            jC.AddRow(masterType, "", desc, "", total, 0);
            jC.AddRow((string)frm.CbbType.SelectedValue, frm.RdrCode.Text, desc, frm.FncSalesNo.ToString(false), 0, total);

            return jC.Save();
        }

        /// <summary>
        /// Modify existing journal entry to correct value
        /// </summary>
        /// <param name="jC"></param>
        /// <param name="fncSalesNoRef"></param>
        /// <returns></returns>
        private bool EditJournalEntriesSalePurchase(JournalEntriesSalePurchaseCreator jC, CounterControl fncSalesNoRef)
        {
            if (!jC.Edit())
                return false;

            jC.ClearCastle();
            jC.ClearJE();

            jC.SetHeader(GetTemplate(), frm.FncSalesNo.ToString(false), frm.CtbDate.Today, frm.CbbType.SelectedValue.ToString(), frm.RdrCode.Text, frm.TxtDescription.Text, frm.GetInvoiceType, frm.FncSalesNoRef.ToString(false));
            jC.AddCastleRow(frm.CbbTaxCode.SelectedValue.ToString(), frm.NtbAmount.Double, frm.NtbTax.Double, frm.CkbBankRestraint.Checked, frm.CkbDeduction.Checked, 
                frm.CkbRestraint.Checked, frm.CbbRestraint.SelectedValue.ToString(), frm.NtbRestraint.Double);

            jC.LoadTemplate();
            jC.ClearEmptyRow();
            return jC.Save();
        }

        /// <summary>
        /// Create a journal entries relates to this invoice
        /// </summary>
        /// <param name="jC"></param>
        /// <returns></returns>
        private bool NewJournalEntriesSalePurchase(JournalEntriesSalePurchaseCreator jC)
        {
            if (!jC.AddNew())
                return false;

            jC.SetHeader(GetTemplate(), frm.FncSalesNo.ToString(false), frm.CtbDate.Today, frm.CbbType.SelectedValue.ToString(), frm.RdrCode.Text, frm.TxtDescription.Text, frm.GetInvoiceType, frm.FncSalesNoRef.ToString(false));
            jC.AddCastleRow(frm.CbbTaxCode.SelectedValue.ToString(), frm.NtbAmount.Double, frm.NtbTax.Double, frm.CkbBankRestraint.Checked, frm.CkbDeduction.Checked,
                frm.CkbRestraint.Checked, frm.CbbRestraint.SelectedValue.ToString(), frm.NtbRestraint.Double);

            jC.LoadTemplate();
            jC.ClearEmptyRow();
            return jC.Save();
        }

        private bool CreatePayment(double payed, string bankcash, string code)
        {
            using (JournalEntriesCreator jC = new JournalEntriesCreator())
            {
                if (!jC.AddNew())
                    return false;
                string desc = string.Format(Properties.Resources.Msg_PayedInvoice, frm.FncSalesNo.ToString(false), frm.CtbDate.Today.ToShortDateString());
                jC.SetHeader(frm.CtbDate.Today, desc);

                jC.AddRow(bankcash, code, desc, frm.FncSalesNo.ToString(false), 0, payed);
                jC.AddRow((string)frm.CbbType.SelectedValue, frm.RdrCode.Text, desc, frm.FncSalesNo.ToString(false), payed, 0);

                return jC.Save();
            }
        }

        private bool SearchPayment(ref string docNo, out double amount, out string code)
        {
            bool found = false;
            amount = 0;
            code = string.Empty;

            if (drJEByNo == null)
                drJEByNo = new DRJournalEntryByDocumentNo();

            if (drJEByNo.Find(frm.CbbManager.GetValue<string>(), frm.FncSalesNo.ToString(false)))
            {
                for (int t = 0; t < drJEByNo.Count; t++)
                {
                    if (drJEByNo.GetValue<double>(PL_JournalEntryDetail.To, t) != 0)
                        amount = drJEByNo.GetValue<double>(PL_JournalEntryDetail.To, t);
                    if (drJEByNo.GetValue<double>(PL_JournalEntryDetail.From, t) != 0)
                    {
                        found = true;
                        docNo = drJEByNo.GetValue<string>(PL_JournalEntryDetail.JournalNo, t);
                        code = drJEByNo.GetValue<string>(PL_JournalEntryDetail.Code, t);
                    }
                }
            }

            return found;
        }

        public override string CreateSlaveQuery(string name)
        {
            QueryBuilder qb = new QueryBuilder(true);
            qb.SetQualified = true;

            if (name == JournalEntrySlave)
            {
                qb.AddSelect(PL_JournalEntry.JournalNo);
                qb.AddSelect(PL_JournalEntry.PostingDate);
                qb.AddSelectAll(PL_JournalEntryDetail.Name);
                qb.AddFrom(PL_JournalEntry.Name);
                qb.AddJoin(QueryBuilder.JoinType.INNER, PL_JournalEntryDetail.JournalNo, PL_JournalEntry.JournalNo);

                qb.AddCompare(PL_JournalEntryDetail.Type, "@p4");
                qb.AddCompare(PL_JournalEntryDetail.Code, "@p5");
                qb.Where += string.Format(" AND ( {0} = @p3 OR {1} = @p3 ) AND {2} IN ({3},{4},{5},{6})",
                    PL_JournalEntryDetail.DocumentNo.QualifyName, PL_JournalEntryDetail.InvoiceNo.QualifyName,
                    PL_JournalEntry.InvoiceType.Name,
                    InvoiceType.E_InvoiceEm.Int(), InvoiceType.E_CreditNoteEm.Int(), InvoiceType.E_DebitNoteEm.Int(),
                    InvoiceType.E_NoInvoice.Int());
            }
            return qb.Query;
        }

        public override List<SqlABParameter> CreateSlaveParam(string name)
        {
            List<SqlABParameter> PList = new List<SqlABParameter>();
            if (name == JournalEntrySlave)
            {
                SqlABParameter p3 = new SqlABParameter("@p3", PL_JournalEntryDetail.DocumentNo);
                p3.Value = "";
                PList.Add(p3);
                SqlABParameter p4 = new SqlABParameter("@p4", PL_JournalEntryDetail.Type);
                p4.Value = "";
                PList.Add(p4);
                SqlABParameter p5 = new SqlABParameter("@p5", PL_JournalEntryDetail.Code);
                p5.Value = "";
                PList.Add(p5);
            }
            return PList;
        }

        public override void SetParameters(DBManager dbManager, IRadarParameters key, DBCollection collection)
        {
            if (collection.Name == JournalEntrySlave)
            {
                frm.Formatter.Text = key[0] as string;
                collection.Parameter[0].Value = frm.Formatter.ToString(false);
                collection.Parameter[1].Value = dbManager.GetColumn<string>(PL_SalesInvoices.Type);
                collection.Parameter[2].Value = dbManager.GetColumn<string>(PL_SalesInvoices.Master);
            }
            base.SetParameters(dbManager, key, collection);
        }

        private string GetTemplate()
        {
            switch(frm.GetInvoiceType)
            {
                case InvoiceType.E_CreditNoteEm:
                    return frm.CkbRestraint.Checked
                                ? AccountingPref.CreditNoteRestraint
                                : frm.CkbDeduction.Checked
                                    ? AccountingPref.CreditNoteDeduction
                                    : AccountingPref.CreditNote;

                case InvoiceType.E_DebitNoteEm:
                    return frm.CkbRestraint.Checked
                                ? AccountingPref.DebitNoteRestraint
                                : frm.CkbDeduction.Checked
                                    ? AccountingPref.DebitNoteDeduction
                                    : AccountingPref.DebitNote;

                case InvoiceType.E_InvoiceEm:
                    return frm.CkbRestraint.Checked || frm.CkbBankRestraint.Checked
                                ? AccountingPref.InvoiceRestraint
                                : frm.CkbDeduction.Checked
                                    ? AccountingPref.InvoiceDeduction
                                    : AccountingPref.Invoice;
                default:
                    System.Diagnostics.Debug.Assert(false, "Unknow type");
                    return "";
                     
            }
        }
    }
}